package CelestialWorkflow;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Calendar;
import java.text.ParseException;

import CelestialDataAccess.*;
import CelestialDataStructures.*;

public class ValidateControl {

    public static final int NULL_FST_NAME = 100;     // First name required
    public static final int NULL_LST_NAME = 101;     // Last name required
    public static final int NULL_EMAIL = 110;        // Email required
    public static final int EMAIL_NT_UNIQUE = 111;   // Email already registered
    public static final int INVALID_EMAIL = 112;     // Invalid email format
    public static final int EMAIL_NT_REG = 113;      // Email not registered
    public static final int ACC_ACTIVATED = 115;     // Email already activated
    public static final int INVALID_CONTACT = 120;   // Invalid contact format
    public static final int INVALID_DOB = 131;       // Invalid DOB
    public static final int NULL_DOB = 132;          // Null DOB
    public static final int INVALID_CC_EXPIRY = 140; // Invalid CC Expiry date
    public static final int CC_EXPIRED = 141;        // CC expired
    public static final int INVALID_CC_NUM = 142;    // Invalid CC number
    public static final int INVALID_CC_ISSUER = 143; // Wrong issuer
    public static final int INVALID_PWD = 150;       // Invalid password
    public static final int NULL_PWD = 151;          // Password required
    public static final int PWD_MISMATCH = 152;      // Password mismatch
    public static final int INVALID_EMP_DATE = 160;  // Invalid Employment Date
    public static final int SYS_ERR = 200;           // Generic system error

    protected HashMap<Integer, String> m_mapErrors = new HashMap<Integer, String>();
    /*************************************************************************/
    /* Get/Set methods */
    public Map<Integer, String> getErrors(){ return m_mapErrors; }
    /*************************************************************************/
    /* Client methods */
    public boolean validateRetypePassword(String pw, String pw2){

        int iNumErrors = m_mapErrors.size();

        if(pw.compareTo(pw2) != 0)
            m_mapErrors.put(PWD_MISMATCH, "Password mismatch");

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public int getPasswordStrength(String pw){

        int iStrength = Validation.getPasswordStrength(pw);

        if(iStrength < 0)
            m_mapErrors.put(INVALID_PWD, "Invalid password");

        if(iStrength == 0)
            m_mapErrors.put(NULL_PWD, "Password required");

        return iStrength;
    }
    /*-----------------------------------------------------------------------*/
    public boolean validatePassword(String pw, String pw2){

        int iNumErrors = m_mapErrors.size();
        int iStrength = Validation.getPasswordStrength(pw);

        if(iStrength < 0)
            m_mapErrors.put(INVALID_PWD, "Invalid password");

        if(iStrength == 0)
            m_mapErrors.put(NULL_PWD, "Password required");

        if(pw.compareTo(pw2) != 0)
            m_mapErrors.put(PWD_MISMATCH, "Password mismatch");

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateNames(String fst_name, String lst_name){

        int iNumErrors = m_mapErrors.size();

        if(fst_name != null && fst_name.length()==0)
            m_mapErrors.put(NULL_FST_NAME, "First name required");

        if(lst_name != null && lst_name.length()==0)
            m_mapErrors.put(NULL_LST_NAME, "Last name required");

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateContact(String contact){

        if(contact.length()==0) return false;

        int iNumErrors = m_mapErrors.size();

        if(!Validation.validatePhone(contact))
            m_mapErrors.put(INVALID_CONTACT, "Invalid contact");

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateCreditCard(String num, int type, String mth, String yr){

        int iNumErrors = m_mapErrors.size();

        /* validate credit card expiry, card number and issuer*/
        validateCreditCardExpiry(mth, yr);
        validateCreditCardNumber(num);
        validateCreditCardIssuer(num, type);

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateCreditCardNumber(String num){

        if(!Validation.validateCreditCard(num)){
            m_mapErrors.put(INVALID_CC_NUM, "Invalid card");
            return false;
        }
        return true;
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateCreditCardExpiry(String mth, String yr){

        if(mth.compareTo("-1")==0 && yr.compareTo("-1")==0)
            return false;

        try{
            Date dtExpire = DateFormat.parse(yr + "-" + mth + "-" + "01");

            if(Calendar.getInstance().getTime().compareTo(dtExpire) > 0){
                m_mapErrors.put(CC_EXPIRED, "Card expired");
                return false;
            }
            else return true;
        } catch (ParseException ex) {
            m_mapErrors.put(INVALID_CC_EXPIRY, "Invalid date"); // mutex with INVALID_CC_EXPIRY
            return false;
        }
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateCreditCardIssuer(String num, int type){

        if(type == -1 || num.length() == 0) return false;

        int iNumErrors = m_mapErrors.size();

        if(!Validation.validateCreditCard(num, type))
            m_mapErrors.put(INVALID_CC_ISSUER, "Wrong issuer");

        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateEmail(int cust_id, String email){

        if(email.length()==0){
            m_mapErrors.put(NULL_EMAIL, "Email required");
            return false;
        }

        int iNumErrors = m_mapErrors.size();

        if(!Validation.validateEmail(email))
            m_mapErrors.put(INVALID_EMAIL, "Invalid email");

        /* see if email is registered by others */
        try{
            if (new UsersDataAccess().isEmailTaken(cust_id, email))
                m_mapErrors.put(EMAIL_NT_UNIQUE, "Already registered");
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System error: " + ex.getMessage());
            return false;
        }
        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateEmail(String email){

        if(email.length()==0){
            m_mapErrors.put(NULL_EMAIL, "Email required");
            return false;
        }
        int iNumErrors = m_mapErrors.size();

        if(!Validation.validateEmail(email))
            m_mapErrors.put(INVALID_EMAIL, "Invalid email");

        /* see if email is registered by others */
        try{
            if (new UsersDataAccess().isEmailRegistered(email))
                m_mapErrors.put(EMAIL_NT_UNIQUE, "Already registered");
        }catch(DataAccessException ex){
            m_mapErrors.put(SYS_ERR, "System error: " + ex.getMessage());
            return false;
        }
        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public boolean validateDOB(String year, String month, String day){

        if(year.length() == 0 && month.length() == 0 && day.length( )==0 ){
            m_mapErrors.put(AccountControl.NULL_DOB, "DOB required");
            return false;
        }
        int iNumErrors = m_mapErrors.size();

        /* check general validity */
        Date dtDOB = Validation.validateDate(year, month, day);
        if(dtDOB == null)
            m_mapErrors.put(INVALID_DOB, "Invalid date");
        else{
            /* check range */
            Calendar calDOB = Calendar.getInstance();
            calDOB.set(Integer.parseInt(year), Integer.parseInt(month), Integer.parseInt(day));

            /* Min 12 years old */
            Calendar calMax = Calendar.getInstance();
            calMax.add(Calendar.YEAR, -12);

            /* Max 100 years old */
            Calendar calMin = Calendar.getInstance();
            calMin.add(Calendar.YEAR, -100);

            if(calDOB.after(calMax) || calDOB.before(calMin))
                m_mapErrors.put(INVALID_DOB, "Invalid date");
        }
        return iNumErrors == m_mapErrors.size();
    }
    /*-----------------------------------------------------------------------*/
    public void clearErrors(){ m_mapErrors.clear(); }
    /*-----------------------------------------------------------------------*/
    public boolean hasError(int err_code){
        return m_mapErrors.containsKey(err_code);
    }
    /*-----------------------------------------------------------------------*/
    public boolean hasError(){ return !m_mapErrors.isEmpty();}
    /*************************************************************************/
}
